﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.Instruments;
using Sasa.QualityTools.CodeAnalysis.Core.Models;
using System.IO;
using Sasa.QualityTools.CodeAnalysis.Core.VisualStudio;
using Sasa.QualityTools.CodeAnalysis.Core.Utilities;

namespace Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.Utilities
{
    [TestFixture]
    public class MetricsOptionBuilderTest
    {
        [TestFixtureTearDown]
        public void TearDownFixture()
        {
            TestCaseDataGenerator.Cleanup();
        }

        [Test]
        [TestCaseSource(typeof(TestCaseDataGenerator), "GenerateForBuildWithProject")]
        public string BuildWithProjectShouldWorkCorrectly(IProject project, Version version)
        {
            return MetricsOptionBuilder.Build(project, version);
        }


        public class TestCaseDataGenerator
        {
            private static readonly string ResourceDir = Path.Combine(Environment.CurrentDirectory, "Resources", "Utilities", "MetricsOptionBuilder");


            public static void Cleanup()
            {
                foreach (var path in Directory.GetFiles(ResourceDir, "*.conf"))
                {
                    File.Delete(path);
                }
            }

            public IEnumerable<TestCaseData> GenerateForBuildWithProject()
            {
                yield return new TestCaseData(null, new Version())
                    .Throws(typeof(ArgumentNullException))
                    .SetName("Build should throw exception when the project is null.");

                yield return new TestCaseData(new DummyProject(), null)
                    .Throws(typeof(ArgumentNullException))
                    .SetName("Build should throw exception when the version is null.");

                yield return new TestCaseData(BuildupProject(enableSearchGac: true), new Version())
                    .Returns(@"/f:""asm.dll"" /o:""bin\CodeMetricsReport.xml"" /sf /gac")
                    .SetName("Build should set /gac option when EnableSearchGac of configuration is true.");

                yield return new TestCaseData(BuildupProject(ignoreGeneratedCode: true), new Version())
                    .Returns(@"/f:""asm.dll"" /o:""bin\CodeMetricsReport.xml"" /sf /igc")
                    .SetName("Build should set /igc option when IgnoreGeneratedCode of configuration is true.");

                var project = BuildupProject();
                project.DependencyDirectories = new List<string> { "a", "b", "c" };
                yield return new TestCaseData(project, new Version())
                    .Returns(@"/f:""asm.dll"" /o:""bin\CodeMetricsReport.xml"" /sf /d:""a"" /d:""b"" /d:""c""")
                    .SetName("Build should set /d options when IProject has dependency directories.");

                yield return BuildShouldRemoveLastBackslashesOfDependencyDirectories();
            }

            private TestCaseData BuildShouldRemoveLastBackslashesOfDependencyDirectories()
            {
                var project = BuildupProject();
                project.DependencyDirectories = new List<string> { "a", "a\\b", "a\\b\\", "a\\b\\c\\\\\\" };
                var version = new Version();
                var result = @"/f:""asm.dll"" /o:""bin\CodeMetricsReport.xml"" /sf /d:""a"" /d:""a\b"" /d:""a\b"" /d:""a\b\c""";
                var name = "Build should remove last backslashes of dependency directories.";
                return new TestCaseData(project, version).Returns(result).SetName(name);
            }

            private DummyProject BuildupProject(bool enableSearchGac = false, bool ignoreGeneratedCode = false, double timeout = 0, string ruleset = null, string dictionary = null)
            {
                var configPath = Path.Combine(ResourceDir, Guid.NewGuid().ToString() + ".conf");
                var config = CodeAnalysisConfiguration.Load(configPath);
                config.EnableSearchGac = enableSearchGac;
                config.IgnoreGeneratedCode = ignoreGeneratedCode;
                config.Timeout = timeout;
                config.RuleSet = ruleset;
                config.Save();

                return new DummyProject
                {
                    AssemblyPath = "asm.dll",
                    TargetDir = "bin",
                    ConfigurationPath = "dummy.xml",
                    Solution = new DummySolution
                    {
                        ConfigurationPath = configPath,
                        FxCopDictionaryPath = dictionary
                    },
                };
            }
        }
    }
}
